package garbagen;

import javax.management.*;
import java.lang.management.*;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Optional;

public class G1GCUtilPrinter {

    private static final DecimalFormat PERCENT_FORMAT = new DecimalFormat("0.00");
    private static final DecimalFormat TIME_FORMAT = new DecimalFormat("0.000");
    
    // G1 特有的内存池名称常量
    private static final String G1_EDEN = "G1 Eden Space";
    private static final String G1_SURVIVOR = "G1 Survivor Space";
    private static final String G1_OLD = "G1 Old Gen";
    private static final String META = "Metaspace";
    private static final String CCS = "Compressed Class Space";

    public static void main(String[] args) {
        printG1GcUtil();
    }

    public static void printG1GcUtil() {
        // 打印表头
        System.out.println("   S0      S1      E       O       M       CCS     YGC     YGCT    FGC    FGCT     GCT");
        
        // 获取内存池和GC MXBeans
        List<MemoryPoolMXBean> memoryPools = ManagementFactory.getMemoryPoolMXBeans();
        List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();

        // 解析G1内存区域使用率
        double s0 = getG1SurvivorUsage(memoryPools, 0); // 当前激活的Survivor区域
        double s1 = getG1SurvivorUsage(memoryPools, 1); // 非激活的Survivor区域
        double eden = getMemoryUsagePercent(memoryPools, G1_EDEN);
        double old = getMemoryUsagePercent(memoryPools, G1_OLD);
        double meta = getMemoryUsagePercent(memoryPools, META);
        double ccs = getMemoryUsagePercent(memoryPools, CCS);

        // 解析GC统计信息
        long ygc = 0;    // 年轻代GC次数
        double ygct = 0; // 年轻代GC时间
        long fgc = 0;    // Full GC次数
        double fgct = 0; // Full GC时间
        
        for (GarbageCollectorMXBean gc : gcBeans) {
            String name = gc.getName();
            long count = gc.getCollectionCount();
            double time = gc.getCollectionTime() / 1000.0;
            
            if (name.contains("Young")) {
                ygc += count;
                ygct += time;
            } else if (name.contains("Old") || name.contains("Mixed") || name.equals("G1 Full GC")) {
                fgc += count;
                fgct += time;
            }
        }
        
        double gct = ygct + fgct; // 总GC时间

        // 格式化输出
        System.out.printf("%6s%7s%7s%7s%7s%7s%8s%9s%6s%9s%9s%n",
                formatPercent(s0),
                formatPercent(s1),
                formatPercent(eden),
                formatPercent(old),
                formatPercent(meta),
                formatPercent(ccs),
                ygc,
                TIME_FORMAT.format(ygct),
                fgc,
                TIME_FORMAT.format(fgct),
                TIME_FORMAT.format(gct));
    }
    
    // 获取G1 Survivor区域使用率
    private static double getG1SurvivorUsage(List<MemoryPoolMXBean> pools, int regionType) {
        // G1 只有一个Survivor池，但JVM会在不同时间使用不同Region
        // 0表示当前激活的Survivor区域，1表示非激活的
        Optional<MemoryPoolMXBean> survivorPool = pools.stream()
                .filter(p -> G1_SURVIVOR.equals(p.getName()))
                .findFirst();
        
        if (survivorPool.isPresent()) {
            // 获取Survivor总使用率
            double survivorUsage = getUsagePercent(survivorPool.get());
            
            // 在真实jstat中，Survivor区域是交替使用的
            // 这里简化处理：非激活区域设为0，激活区域设为实际使用率
            return (regionType == 0) ? survivorUsage : 0.0;
        }
        return 0.0;
    }
    
    // 获取标准内存池使用率
    private static double getMemoryUsagePercent(List<MemoryPoolMXBean> pools, String name) {
        Optional<MemoryPoolMXBean> pool = pools.stream()
                .filter(p -> name.equals(p.getName()))
                .findFirst();
        
        return pool.map(G1GCUtilPrinter::getUsagePercent).orElse(0.0);
    }
    
    // 计算单个内存池使用率百分比
    private static double getUsagePercent(MemoryPoolMXBean pool) {
        MemoryUsage usage = pool.getUsage();
        long max = usage.getMax();
        
        if (max > 0) {
            return (double) usage.getUsed() * 100 / max;
        }
        
        // 对于没有固定最大值的内存池（如元空间）
        return (double) usage.getUsed() * 100 / usage.getCommitted();
    }
    
    // 格式化百分比输出
    private static String formatPercent(double value) {
        return PERCENT_FORMAT.format(value);
    }
}